package me.seawenc.db.migration.service;

import com.alibaba.fastjson.JSON;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.stream.Collectors;
import me.seawenc.db.migration.bean.DatabaseBean;
import me.seawenc.db.migration.bean.FileConfig;
import me.seawenc.db.migration.bean.TableBean;
import me.seawenc.db.migration.dbengine.DbType;
import me.seawenc.db.migration.dbengine.IEngineService;
import me.seawenc.db.migration.dbengine.impl.engines.bean.TableNameBean;
import me.seawenc.db.migration.helper.Optionalx;
import me.seawenc.db.migration.helper.YmlHelper;
import me.seawenc.db.migration.service.translator.BaseTranslator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import static me.seawenc.db.migration.dbengine.DbType.findTypeByDriver;

public class DatabaseService {
    Logger logger = LogManager.getLogger(DatabaseService.class);
    IEngineService dbEngine;
    String configPath;
    DbType dsType;

    public DatabaseService(String configPath, String confKeyPrefix) throws Exception {
        FileConfig config = createFileParameters(configPath,confKeyPrefix);
        dbEngine = DbType.findDbEngine(config);
        dsType = findTypeByDriver(config.getJdbcDriver());
        this.configPath = configPath;
    }

    public DatabaseBean buildDatabaseStructure(boolean needDetail) throws Exception {
        List<TableBean> tables = findAllTableInfo(needDetail);
        // 如果开启了只转移无主建的表，则过滤掉无主键的表
        tables=filterNoPkTableIfEnable(tables);

        DatabaseBean database=new DatabaseBean();
        database.setVersion(dbEngine.findVersion());
        database.setDbType(dsType);
        database.setDbTables(tables);
        return database;
    }

    private List<TableBean> filterNoPkTableIfEnable(List<TableBean> tables) {
        String onlyNoPkTable = YmlHelper.getConfig(configPath,"migration.only-no-primarykey-table", "false");
        if("true".equals(onlyNoPkTable)){
            String filterdTables = tables.stream().filter(t -> t.hasPrimaryKey()).map(t->t.getTableName()).collect(Collectors.joining(","));
            logger.info(String.format("开启了无主键表过滤，\u001B[1;32m过滤掉有主键的表有：\u001B[0m %s" ,filterdTables));
            return tables.stream().filter(t->!t.hasPrimaryKey()).collect(Collectors.toList());
        }
        return tables;
    }

    /**
     * 将物理模型转为逻辑模型（将mysql类型做为逻辑模型，以减少一种独创的逻辑数据库类型）
     *
     * @param srcDatabase
     * @return
     */
    public DatabaseBean physicalToLogicModel(DatabaseBean srcDatabase) {
        BaseTranslator translator = dbEngine.getTranslator();
        DatabaseBean logicDatabase = new DatabaseBean();
        logicDatabase.setVersion("8.0");
        logicDatabase.setDbType(DbType.MYSQL);
        logicDatabase.setPhysicalDatabase(srcDatabase);
        for(TableBean table:srcDatabase.getDbTables()){
            // copy对象
            TableBean logicTable= JSON.parseObject(JSON.toJSONString(table),TableBean.class);
            // 将字段类型转为逻辑类型字段类型转为逻辑类型
            logicTable.getFields().forEach(f-> translator.filedType2Logic(f));
            // 后面需转换的还有很多 fixme

            // 添加到逻辑数据库
            logicDatabase.getDbTables().add(logicTable);
        }
        return logicDatabase;
    }

    public DatabaseBean logicModelToPhysical(DatabaseBean logicDatabase) throws Exception {
        BaseTranslator translator = dbEngine.getTranslator();
        DatabaseBean targetPhysicalDatabase = new DatabaseBean();
        targetPhysicalDatabase.setVersion(dbEngine.findVersion());
        targetPhysicalDatabase.setDbType(dsType);
        for(TableBean table:logicDatabase.getDbTables()){
            // copy对象
            TableBean physicalTable= JSON.parseObject(JSON.toJSONString(table),TableBean.class);
            // 将字段类型转为逻辑类型字段类型转为逻辑类型
            physicalTable.getFields().forEach(f-> translator.filedType2Physical(f));
            // 后面需转换的还有很多 fixme

            // 添加到逻辑数据库
            targetPhysicalDatabase.getDbTables().add(physicalTable);
        }
        // fixme
        return targetPhysicalDatabase;
    }

    private List<TableBean> findAllTableInfo(boolean needDetail) throws Exception {
        List<TableNameBean> allTables = dbEngine.findAllTables();
        allTables=filterTable(allTables);
        List<TableBean> tables = new ArrayList<>();
        for(TableNameBean tableNameBean:allTables){
            if(needDetail){
                tables.add(dbEngine.findTableDetail(tableNameBean.getTableName()));
            }else{
                // 不需要外键等信息
                tables.add(dbEngine.findTableInfo(tableNameBean.getTableName()));
            }
        }
        return tables;
    }



    /**
     * 根据配置项过滤掉不需要同步的表
     * @param tables
     * @return
     */
    private List<TableNameBean> filterTable(List<TableNameBean> tables) {
        Properties props = YmlHelper.yamlFile2PropsFilter(configPath,"migration");

        String includeTables=props.getProperty(".include-table");
        String excludeTables=props.getProperty(".exclude-table");



        if(Optionalx.isPresent(includeTables)){
            logger.info("数据迁移，本次只迁移\u001B[1;32m指定的表："+ includeTables+"\u001B[0m");
            final String tableNames=String.format(",%s,",includeTables);
            return tables.stream().filter(table -> tableNames.contains(String.format(",%s,",table.getTableName()))).collect(Collectors.toList());

        }
        if(!Optionalx.isPresent(includeTables) && Optionalx.isPresent(excludeTables)){
            logger.info("数据迁移，本次迁移需\u001B[1;32m过滤掉配置文件中指定表："+ excludeTables+"\u001B[0m");
            final String tableNames=String.format(",%s,",excludeTables);
            return tables.stream().filter(table -> !tableNames.contains(table.getTableName())).collect(Collectors.toList());
        }
        return tables;
    }


    private static FileConfig createFileParameters(String configPath,String confKeyPrefix) throws Exception {
        Properties props = YmlHelper.yamlFile2PropsFilter(configPath,confKeyPrefix);
        return FileConfig.getInstance(props);
    }


    public String buildPhysicalDdlSql(DatabaseBean srcToTargetDatabase) {
        List<String> sqls=new ArrayList<>();
        for (TableBean table: srcToTargetDatabase.getDbTables()) {
            sqls.add(dbEngine.getTranslator().buildCreateTableSql(table));
        }

        return sqls.stream().collect(Collectors.joining("\n"));
    }
}
